//
//  GridController.m
//  FirstGridApp
//
//  Created by Andrew Spina on 4/10/10.
//  Copyright 2010 STScI. All rights reserved.
//

#import "GridController.h"
#import "iD20AppDelegate.h"

@implementation GridController

@synthesize gridScrollView;
@synthesize masterView;
// A double array of Strings. A light weight datamodel.
@synthesize map;
@synthesize cells;
@synthesize activeTokenLocation;
@synthesize cellUIToPointDict;
@synthesize nullToken;
@synthesize tokenArray;

const CGFloat kScrollObjHeight    = 640;
const CGFloat kScrollObjWidth    = 480;

// TODO migrate these fields and map into a data class.
const CGFloat cell_dim   = 20;
const CGFloat cell_x_off = 9;
const CGFloat cell_y_off = -1;
const int cell_count_x = 31;
const int cell_count_y = 39;
const CGFloat initial_zoom = 2.5;


- (Token*) tokenAtPoint: (Point2d *) point {
	Token *token = [[map objectAtIndex:point.x] objectAtIndex:point.y];
	return token;
}

- (GridCellUIView*) cellForPoint: (Point2d *) point {
	return [[cells objectAtIndex:point.x] objectAtIndex:point.y];
}

- (void) setTokenAtPoint: (Point2d *) point newToken: (Token *) token{
	NSLog(@"Changing Token at %@ to %@", point, token);
	[[map objectAtIndex:point.x] replaceObjectAtIndex:point.y withObject:token];
	NSString * tokenName = token.name;
	[[self cellForPoint:point] setToken:tokenName];
	
	[token setXPosition:[NSNumber numberWithInt:point.x]];
	[token setYPosition:[NSNumber numberWithInt:point.y]];
	NSError *error;
	if (![managedObjectContext save:&error]) {
		NSLog(@"Error saving state");
		NSLog(@"%@", error);
	}
}

- (Point2d*) pointForCell: (GridCellUIView *) cell {
	return [self.cellUIToPointDict objectForKey:[NSValue valueWithPointer:cell]];
}

- (Token*) makeToken: (NSString *) name x: (int) x y: (int) y {
	Token *token = (Token *)[NSEntityDescription insertNewObjectForEntityForName:@"Token" inManagedObjectContext:managedObjectContext];
	token.name = name;
	token.speed = [NSNumber numberWithInt: random() % 7];
	token.xPosition = [NSNumber numberWithInt:x];
	token.yPosition = [NSNumber numberWithInt:y];
	return token;
}

- (Token*) getNullToken {
	if (nullToken == nil) {
		nullToken = [self makeToken:@"Nil Token" x:-1 y:-1];
	}
	return nullToken;
}

- (bool) isToken: (Token *) token {
	return token != [self getNullToken];
}

- (bool) isTokenAtPoint: (Point2d *) point {
	return [self isToken: [self tokenAtPoint:point]];
}

- (void) initMapData {
	self.map = [NSMutableArray arrayWithCapacity:cell_count_x];
	for (int x = 0; x <= cell_count_x; x++) {
		[map insertObject:[NSMutableArray arrayWithCapacity:cell_count_y] atIndex:x];
		for (int y = 0; y <= cell_count_y; y++) {
			[[map objectAtIndex:x] insertObject:[self getNullToken] atIndex:y];
		}
	}
}

- (void) loadTokens {
	managedObjectContext = [FirstGridAppAppDelegate getManagedObjectContext];
	
	NSLog(@"Load Tokens");
	NSFetchRequest *request = [[NSFetchRequest alloc] init];
	NSEntityDescription *entity = [NSEntityDescription entityForName:@"Token" inManagedObjectContext:managedObjectContext];
	[request setEntity:entity];
	
	NSError *error;
	NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
	if (mutableFetchResults == nil) {
		NSLog(@"Error loading state");
	}
	
	for (int i = 0; i < [mutableFetchResults count]; i++) {
		Token *token = (Token *)[mutableFetchResults objectAtIndex:i];
		int x = [token.xPosition intValue];
		int y = [token.yPosition intValue];
		if (![token.name isEqualToString:@"Nil Token"]) {
//			NSLog(@"Token %@ at (%d,%d)", token.name, x, y);
			[[map objectAtIndex:x] replaceObjectAtIndex:y withObject:token];
		}
	}
	
	[self setTokenArray:mutableFetchResults];
	[mutableFetchResults release];
	[request release];
}

- (void) loadMapData {
	NSLog(@"Load Default Tokens");
	for (int x = 0; x <= cell_count_x; x++) {
		for (int y = 0; y <= cell_count_y; y++) {
			Token *token = nil;
			if(x % 3 == 0 && y % 3 == 0) {
				if( x % 9 == 0 ) {
				    token = [self makeToken:@"RobToken.png" x:x y:y];
				} else if( x % 9 == 3 ) {
					token = [self makeToken:@"GaryToken.png" x:x y:y];
				} else {
					token = [self makeToken:@"AndyToken.png" x:x y:y];
				}
			}
			if (token != nil) {
				[[map objectAtIndex:x] replaceObjectAtIndex:y withObject:token];
			}
		}
	}
}

- (CGRect) rectForPoint: (Point2d*) point {
	return CGRectMake(point.x*cell_dim + cell_x_off, point.y*cell_dim + cell_y_off, cell_dim, cell_dim);
}

- (void) addGridCellAtPoint: (Point2d*) point {
	GridCellUIView *cell = [[GridCellUIView alloc] initWithFrame:[self rectForPoint: point]];
	[cell retain];
	cell.controller = self;
	[cell setToken:[self tokenAtPoint:point].name];
	[self.masterView addSubview:cell];
	[self.cellUIToPointDict setObject:point forKey:[NSValue valueWithPointer:cell]];
	[[cells objectAtIndex:point.x] insertObject:cell atIndex:point.y];
}

- (void) addMarkerButtons {
	self.cellUIToPointDict  = [[NSMutableDictionary alloc] init];
	self.cells = [NSMutableArray arrayWithCapacity:cell_count_x];
	for (int x = 0; x <= cell_count_x; x++){
		[cells insertObject:[NSMutableArray arrayWithCapacity:cell_count_y] atIndex:x];
		for (int y = 0; y <= cell_count_y; y++){
			Point2d *point = [Point2d createPointAtX:x andY:y];
			[self addGridCellAtPoint: point];
		}
	}
}

- (void) configureMasterView {
	UIImage *image = [UIImage imageNamed:@"map.jpg"];
	UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
	self.masterView = [UIView alloc];
	[masterView initWithFrame:imageView.frame];
	[masterView addSubview:imageView];
	[self addMarkerButtons];
}

- (void) configureScrollView {
	[self.gridScrollView addSubview:masterView];
	[self.gridScrollView setZoomScale:initial_zoom animated:NO];
	[self.gridScrollView setContentSize:CGSizeMake(masterView.bounds.size.height, masterView.bounds.size.width)];
}

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
	managedObjectContext = [FirstGridAppAppDelegate getManagedObjectContext];
    [super viewDidLoad];
	[self initMapData];
	[self loadTokens];
	if (tokenArray == nil || [tokenArray count] == 0) {
		[self loadMapData];
	}
	[self configureMasterView];
	[self configureScrollView];	
}

/*
 // Override to allow orientations other than the default portrait orientation.
 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
 // Return YES for supported orientations
 return (interfaceOrientation == UIInterfaceOrientationPortrait);
 }
 */

- (void)didReceiveMemoryWarning {
	// Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
	
	// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
	// Release any retained subviews of the main view.
	// e.g. self.myOutlet = nil;
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
	return masterView;
}

- (void) setAreaColor: (Point2d*) point color: (UIColor *) color size: (int) size colorTokens: (BOOL) colorTokens {
	for(int x = MAX(-1 * size + point.x, 0); x <= MIN(size + point.x, cell_count_x); x++){
		for(int y = MAX(-1 * size + point.y, 0); y <= MIN(size + point.y, cell_count_y); y++){
			if(colorTokens || ! [self isTokenAtPoint:[Point2d createPointAtX:x andY:y]]){
				[self cellForPoint:[Point2d createPointAtX:x andY:y]].bgcolor = color;
			}
		}			
	}
}

- (void) showMovementZone: (Point2d*) point size: (int) size {
	// int speed = [[self tokenAtPoint:point].speed intValue];
	[self setAreaColor: point color:[UIColor colorWithRed:0 green:.2 blue:.05 alpha:.5] size: size colorTokens: NO];
}

- (void) hideMovementZone: (Point2d*) point size: (int) size {
	// int speed = [[self tokenAtPoint:point].speed intValue];
	[self setAreaColor: point color:[UIColor clearColor] size: size colorTokens: YES];
}

- (BOOL) token: (Point2d *) origin canReach: (Point2d*) destination speed: (int) speed {
	// int speed = [[self tokenAtPoint:activeTokenLocation].speed intValue];
	return ABS(origin.x - destination.x) <= speed && ABS(origin.y - destination.y) <= speed;
}

- (void) tapCell: (Point2d*) point {
	[self cellTapped: [self cellForPoint:point]];
}

- (void) cellTapped: (GridCellUIView *) cell {
	Point2d* point = [self pointForCell:cell];
	bool isToken = [self isTokenAtPoint:point];
	if(activeTokenLocation == nil){
		if(isToken){
			NSLog(@"TOKEN ACTIVATED: %@", point);
			activeTokenLocation = point;
			cell.highlighted = YES;
			[self showMovementZone:point size:[[self tokenAtPoint:activeTokenLocation].speed intValue]];
		} else {
			NSLog(@"CAN'T activate: %@", point);
		}
	} else {
		if(! isToken && [self token: activeTokenLocation canReach:point speed:[[self tokenAtPoint:activeTokenLocation].speed intValue]]){
			NSLog(@"TOKEN MOVED: From %@ To: %@", activeTokenLocation, point);
			Token *lTokenToMove = [self tokenAtPoint: activeTokenLocation];
			[self setTokenAtPoint:point newToken:lTokenToMove];
			[self setTokenAtPoint:activeTokenLocation newToken:[self getNullToken]];
			[self cellForPoint:activeTokenLocation].highlighted = NO;
			[self hideMovementZone:activeTokenLocation size:[lTokenToMove.speed intValue]];
			activeTokenLocation = nil;
		} else if (point == activeTokenLocation) {
			NSLog(@"TOKEN MOVE CANCELLED: From %@ To: %@", activeTokenLocation, point);
			[self hideMovementZone:activeTokenLocation size:[[self tokenAtPoint:activeTokenLocation].speed intValue]];
			activeTokenLocation = nil;
			cell.highlighted = NO;
		}
	}
}

- (void)dealloc {
    [super dealloc];
	[masterView dealloc];
}

@end
